package top.xia17.plugins.fast.common.database.dynamic;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import top.xia17.plugins.fast.common.exceptions.BadConfigException;
import top.xia17.plugins.fast.common.exceptions.BadRequestException;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据源管理
 *
 * @author xia17
 * @date 2021/11/24
 */
@Slf4j
@RequiredArgsConstructor
public class DsManager {

    private final DynamicRoutingDataSource dataSource;
    private final DefaultDataSourceCreator dataSourceCreator;
    private DatasourceLoader datasourceLoader;

    private final Map<String, DatasourceInfo> dsMap = new HashMap<>(8);

    public DsManager(DynamicRoutingDataSource dataSource, DefaultDataSourceCreator dataSourceCreator, DatasourceLoader datasourceLoader) {
        this.dataSource = dataSource;
        this.dataSourceCreator = dataSourceCreator;
        this.datasourceLoader = datasourceLoader;
    }

    /**
     * 获取所有数据源
     *
     * @return /
     */
    public Map<String, DataSource> all() {
        return dataSource.getDataSources();
    }

    /**
     * 将DataSourceInfo转换成DataSourceProperty
     *
     * @param info /
     * @return /
     */
    private DataSourceProperty toProperty(DatasourceInfo info) {
        DataSourceProperty property = new DataSourceProperty();
        property.setDriverClassName(info.getDriver());
        property.setUrl(info.getUrl());
        property.setUsername(info.getUsername());
        property.setPassword(info.getPassword());
        property.setPoolName(info.getDsName());
        return property;
    }

    /**
     * 添加数据源
     *
     * @param info /
     */
    public synchronized void add(DatasourceInfo info) {
        DataSourceProperty property = this.toProperty(info);
        DataSource dataSource = dataSourceCreator.createDataSource(property);
        this.dataSource.addDataSource(info.getDsName(), dataSource);
        dsMap.put(info.getDsName(), info);
    }

    /**
     * 添加数据源
     *
     * @param infos /
     */
    public synchronized void addAll(List<DatasourceInfo> infos) {
        infos.forEach(this::add);
    }

    /**
     * 删除数据源
     *
     * @param name /
     */
    public synchronized void remove(String name) {
        dataSource.removeDataSource(name);
        dsMap.remove(name);
    }

    /**
     * 是否存在
     *
     * @return /
     */
    public boolean exist(String name) {
        return this.all().containsKey(name);
    }

    /**
     * 是否不存在
     *
     * @return /
     */
    public boolean notExist(String name) {
        return !this.exist(name);
    }


    /**
     * 如果dsMap中不存在则从loader里面load ， loader里面也没有则抛出异常
     */
    public void loadOrElseThrow(String name) {
        if (this.exist(name)) {
            return;
        }
        synchronized (this) {
            if (this.exist(name)) {
                return;
            }
            if (datasourceLoader == null) {
                throw new BadConfigException("配置异常，dataSourceLoader is null！");
            }
            DatasourceInfo dataSourceInfo = datasourceLoader.load(name);
            if (dataSourceInfo == null) {
                throw new BadRequestException("未找到数据源" + name + "的信息");
            }
            this.add(dataSourceInfo);
        }
    }

    /**
     * 获取数据库信息
     *
     * @param name /
     * @return /
     */
    public DatasourceInfo getInfo(String name) {
        return this.dsMap.get(name);
    }

}
